package com.yt.lxh.acl.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yt.lxh.acl.mapper.AdminMapper;
import com.yt.lxh.acl.mapper.RoleUserMapper;
import com.yt.lxh.acl.service.AdminService;
import com.yt.lxh.common.exception.*;
import com.yt.lxh.common.result.ResultCodeEnum;
import com.yt.lxh.common.service.CacheService;
import com.yt.lxh.common.service.CheckLogin;
import com.yt.lxh.common.utils.JwtUtils;
import com.yt.lxh.common.utils.MD5AddSolt;
import com.yt.lxh.constant.RedisEnum;
import com.yt.lxh.constant.SQLConstant;
import com.yt.lxh.dto.admin.AdminDto;
import com.yt.lxh.dto.admin.AssginRoleDto;
import com.yt.lxh.dto.system.LoginDto;
import com.yt.lxh.model.acl.Admin;
import com.yt.lxh.model.acl.RoleUser;
import com.yt.lxh.vo.system.LoginVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements AdminService {
    @Autowired
    private AdminMapper adminMapper;

    @Autowired
    private CacheService cacheService;
    @Autowired
    private CheckLogin checkLogin;
    @Autowired
    private RoleUserMapper roleUserMapper;
    /**
     * 插入用户数据
     * @param admin 用户数据
     * @return 受影响的行数
     */
    @Override
    public void addAdmin(Admin admin,String token) {
        // 根据参数admin对象获取注册的用户名
        String username = admin.getUsername();
        // 调用持久层的Admin findByAdminName(String username)方法，根据用户名查询用户数据
        Admin result = adminMapper.findByAdminName(username);
        // 判断查询结果是否不为null
        if (result != null) {
            // 是：表示用户名已被占用，则抛出UsernameDuplicateException异常
            throw new UsernameDuplicateException(ResultCodeEnum.DATA_EXIST, "尝试注册的用户名[" + username + "]已经被占用");
        }
        // 创建当前时间对象
        Date now = new Date();
        // 加密后的密码
        String salt = UUID.randomUUID().toString().toUpperCase();
        MD5AddSolt md5AddSolt = new MD5AddSolt();
        String md5Password = md5AddSolt.getMD5Password(admin.getPassword(), salt);
        // 数据储存加密密码
        admin.setPassword(md5Password);
        // 数据储存盐值
        admin.setSalt(salt);
        //根据token获取当前用户
        Admin currentAdmin = checkLogin.checkAdminLogin();
        //补全其他数据
        admin.setCreateUser(currentAdmin.getUsername());
        admin.setCreateTime(now);
        admin.setUpdateUser(currentAdmin.getUsername());
        admin.setUpdateTime(now);

        // 表示用户名没有被占用，则允许注册
        // 调用持久层Integer addAdmin(Admin admin)方法，执行注册并获取返回值(受影响的行数)
        Integer rows = adminMapper.addAdmin(admin);
        // 判断受影响的行数是否不为1
        if (rows != 1) {
            // 是：插入数据时出现某种错误，则抛出SqlHandlerException异常
            throw new SqlHandlerException(SQLConstant.INSERT_FAIL + " ---> AdminServiceImpl.addAdmin");
        }
    }

    /**
     * 根据用户名查询用户数据
     * @param username 用户名
     * @return 匹配的用户数据，如果没有匹配的数据，则返回null
     */
    @Override
    public Admin findByAdminName(String username) {
        Admin adminByUsername = adminMapper.findByAdminName(username);
        return adminByUsername;
    }



    /**
     * 用户登录
     * @param loginDto 前端返回的数据
     * @return 后端封装给前端的数据
     */
    @Override
    public LoginVo login(LoginDto loginDto) {

        String userName = loginDto.getUsername();
        // 获取输入验证码和存储到redis的key名称
        String captcha = loginDto.getCaptcha();
        String codeKey = loginDto.getCodeKey();
        // 根据获取的redis里面key，查询redis里面存储验证码
        String redisCode = cacheService.get(RedisEnum.ADMIN_VALIDATE.getMessage() + codeKey);
        // 比较输入的验证码和redis存储验证码是否一致
       if (StrUtil.isEmpty(redisCode)||!StrUtil.equalsIgnoreCase(redisCode,captcha)){
            // 如果不一致，提示用户，校验失败
            throw new ValidateCodeException(ResultCodeEnum.VALIDATECODE_ERROR);
        }
        // 如果一致，删除redis里面验证码
        cacheService.delete(RedisEnum.ADMIN_VALIDATE.getMessage()+codeKey);

        // 调用adminMapper的findByAdminName()方法，根据参数username查询用户数据
        Admin adminByUsername = adminMapper.findByAdminName(loginDto.getUsername());
        // 判断查询结果是否为null
        if (adminByUsername == null) {
            // 是：抛出UserNotFoundException异常
            throw new ServiceException(ResultCodeEnum.DATA_NOT_EXIST, "用户数据不存在");
        }
        // 从查询结果中获取盐值
        String salt = adminByUsername.getSalt();
        // 调用getMd5Password()方法，将参数password和salt结合起来进行加密
        MD5AddSolt md5AddSolt = new MD5AddSolt();
        String md5Password = md5AddSolt.getMD5Password(loginDto.getPassword(), salt);
        // 判断查询结果中的密码，与以上加密得到的密码是否不一致
        if (!adminByUsername.getPassword().equals(md5Password)){
            // 是：抛出PasswordNotMatchException异常
            throw new PasswordNotMatchException(ResultCodeEnum.LOGIN_PASSWORD_ERROR);
        }

        //如果密码一致，登录成功，如果密码不一致登陆失败
        //生成管理员唯一标识：token
        String adminToken = JwtUtils.createAdminToken(Integer.valueOf(adminByUsername.getId().toString()));
        //把登录成功用户信息放到redis里面
        cacheService.setEx(RedisEnum.ADMIN.getMessage()+adminToken,
                            JSON.toJSONString(adminByUsername),
                            7,
                            TimeUnit.DAYS);
        // 创建新的Admin对象
        LoginVo loginVo = new LoginVo();
        // 将查询结果中的id、username、avatar封装到新的user对象中
        loginVo.setToken(adminToken);
        return loginVo;
    }

    @Override
    public Page<Admin> selectAdminListPage(Page<Admin> pageInfo) {
        return null;
    }

    /**
     * 获取当前登录用户信息
     * @param token
     * @return
     */
    @Override
    public Admin getUserInfo(String token) {
        String adminJson = cacheService.get(RedisEnum.ADMIN.getMessage() + token);
        Admin admin = JSON.parseObject(adminJson, Admin.class);
        return admin;
    }

    /**
     * 管理员登出
     * @param token
     */
    @Override
    public void logout(String token) {
        cacheService.delete(RedisEnum.ADMIN.getMessage()+token);
    }

    /**
     * 管理员列表
     * @param pageParams
     * @param adminDto
     * @return
     */
    @Override
    public IPage<Admin> findByPage(Page<Admin> pageParams, AdminDto adminDto) {
        String userName = adminDto.getUserName();
        String createTimeBegin = adminDto.getCreateTimeBegin();
        String createTimeEnd = adminDto.getCreateTimeEnd();
        LambdaQueryWrapper<Admin> wrapper = new LambdaQueryWrapper<>();
        if (!StrUtil.isEmpty(userName)){
            wrapper.like(Admin::getUsername,userName);
        }
        if (!StrUtil.isEmpty(createTimeBegin) && !StrUtil.isEmpty(createTimeEnd)) {
            wrapper.between(Admin::getCreateTime,createTimeBegin,createTimeEnd);
        }
        Page<Admin> adminPage = adminMapper.selectPage(pageParams, wrapper);
        return adminPage;
    }

    /**
     * 用户分配角色
     * @param assginRoleDto
     * @param token
     */
    @Override
    public void doAssign(AssginRoleDto assginRoleDto,String token) {
        //1 根据userId删除用户之前分配角色数据
        roleUserMapper.delete(Wrappers.<RoleUser>lambdaUpdate().eq(RoleUser::getAdminId,assginRoleDto.getAdminId()));
        //2 重新分配数据
        List<String> roleIdList = assginRoleDto.getRoleIdList();

        //遍历得到每个角色id
        for (String roleId:roleIdList) {
            RoleUser roleUser = new RoleUser();
            Date now = new Date();
            roleUser.setRoleId(roleId);
            roleUser.setAdminId(assginRoleDto.getAdminId());
            //根据token获取当前用户
            Admin currentAdmin = checkLogin.checkAdminLogin();
            //补全其他数据
            roleUser.setCreateUser(currentAdmin.getUsername());
            roleUser.setCreateTime(now);
            roleUser.setUpdateUser(currentAdmin.getUsername());
            roleUser.setUpdateTime(now);
            roleUserMapper.insert(roleUser);
        }
    }

    /**
     * 管理员修改
     * @param admin
     */
    @Override
    public void updateAdmin(Admin admin) {
        adminMapper.updateById(admin);
    }

    /**
     * 管理员删除
     * @param adminId
     */
    @Override
    public void deleteById(Integer adminId) {
        adminMapper.deleteById(adminId);
    }

}
